<template>
  <div class="upload-component">
    <el-upload
      ref="uploadRef"
      :http-request="customUpload"
      :multiple="props.multiple"
      :disabled="props.disabled"
      :show-file-list="props.showFileList"
      :drag="props.drag"
      :before-upload="beforeUpload"
      class="upload-component"
    >
      <!-- 图片预览模式 -->
      <div v-if="uploadType === 'image' && !drag" class="image-upload-content">
        <img
          v-if="imageUrl"
          :src="imageUrl"
          :class="imageClass"
          :style="imageStyle"
        />
        <div v-else class="upload-placeholder" :style="placeholderStyle">
          <div class="upload-content">
            <el-icon class="upload-icon"><Plus /></el-icon>
            <div class="upload-text">{{ placeholder }}</div>
          </div>
        </div>
      </div>

      <!-- 拖拽上传模式 -->
      <div v-else-if="drag" class="drag-upload-content">
        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
        <div class="el-upload__text">
          将文件拖到此处，或<em>点击上传</em>
        </div>
        <div class="el-upload__tip" v-if="tip">{{ tip }}</div>
      </div>

      <!-- 按钮上传模式 -->
      <div v-else class="button-upload-content">
        <el-button :type="props.buttonType" :size="props.buttonSize" :loading="isUploading">
          <el-icon><Upload /></el-icon>
          {{ props.buttonText }}
        </el-button>
      </div>

      <!-- 上传提示 -->
      <template #tip v-if="props.tip && !props.drag">
        <div class="el-upload__tip">{{ props.tip }}</div>
      </template>
    </el-upload>

    <!-- 上传进度 -->
    <el-progress
      v-if="props.showProgress && isUploading"
      :percentage="uploadProgress"
      :status="progressStatus"
      class="upload-progress"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch } from 'vue';
import { ElMessage, ElProgress } from 'element-plus';
import { Plus, Upload, UploadFilled } from '@element-plus/icons-vue';
import type { UploadProps, UploadFile, UploadProgressEvent } from 'element-plus';
import { createAttachment } from '@/api/system/attachment';

// 定义组件属性
interface Props {
  // 上传类型：image(图片)、file(文件)、button(按钮)
  uploadType?: 'image' | 'file' | 'button';
  // 上传接口地址
  action?: string;
  // 请求头
  headers?: Record<string, any>;
  // 额外的上传数据
  data?: Record<string, any>;
  // 文件类型限制
  accept?: string;
  // 文件大小限制(MB)
  maxSize?: number;
  // 允许的文件类型
  allowedTypes?: string[];
  // 是否支持多选
  multiple?: boolean;
  // 是否禁用
  disabled?: boolean;
  // 是否显示文件列表
  showFileList?: boolean;
  // 是否拖拽上传
  drag?: boolean;
  // 占位符文本
  placeholder?: string;
  // 提示文本
  tip?: string;
  // 按钮文本
  buttonText?: string;
  // 按钮类型
  buttonType?: 'primary' | 'success' | 'warning' | 'danger' | 'info';
  // 按钮大小
  buttonSize?: 'large' | 'default' | 'small';
  // 图片样式类名
  imageClass?: string;
  // 图片样式
  imageStyle?: Record<string, any>;
  // 占位符样式
  placeholderStyle?: Record<string, any>;
  // 上传组件样式类名
  uploadClass?: string;
  // 是否显示上传进度
  showProgress?: boolean;
  // 当前图片URL（用于回显）
  modelValue?: string;
}

// 定义事件
interface Emits {
  (e: 'update:modelValue', value: string): void;
  (e: 'success', url: string, file: UploadFile, response: any): void;
  (e: 'error', error: Error, file: UploadFile): void;
  (e: 'progress', event: any, file: UploadFile): void;
  (e: 'before-upload', file: UploadFile): boolean | Promise<boolean>;
}

// 设置默认值
const props = withDefaults(defineProps<Props>(), {
  uploadType: 'image',
  action: '/system/api/attachment',
  maxSize: 2,
  allowedTypes: () => ['image/jpeg', 'image/png', 'image/gif'],
  multiple: false,
  disabled: false,
  showFileList: false,
  drag: false,
  placeholder: '上传图片',
  buttonText: '点击上传',
  buttonType: 'primary',
  buttonSize: 'default',
  showProgress: true,
  modelValue: ''
});

const emit = defineEmits<Emits>();

// 响应式数据
const isUploading = ref(false);
const uploadProgress = ref(0);
const imageUrl = ref(props.modelValue);

// 计算属性
const uploadAction = computed(() => props.action);
const uploadHeaders = computed(() => {
  const token = localStorage.getItem('token');
  return {
    'Authorization': token ? `Bearer ${token}` : '',
    ...props.headers
  };
});
const uploadData = computed(() => props.data || {});
const progressStatus = computed(() => {
  if (uploadProgress.value === 100) return 'success';
  if (uploadProgress.value > 0) return '';
  return '';
});

// 监听modelValue变化
watch(() => props.modelValue, (newVal) => {
  imageUrl.value = newVal;
});

// 上传前验证
const beforeUpload: UploadProps['beforeUpload'] = (file) => {
  // 文件类型验证
  if (props.allowedTypes.length > 0 && !props.allowedTypes.includes(file.type)) {
    ElMessage.error(`只能上传 ${props.allowedTypes.join(', ')} 格式的文件`);
    return false;
  }

  // 文件大小验证
  const isLtMaxSize = file.size / 1024 / 1024 < props.maxSize;
  if (!isLtMaxSize) {
    ElMessage.error(`文件大小不能超过 ${props.maxSize}MB`);
    return false;
  }

  isUploading.value = true;
  uploadProgress.value = 0;
  return true;
};

// 上传进度
const onProgress = (event: UploadProgressEvent) => {
  uploadProgress.value = Math.round(event.percent || 0);
};

// 自定义上传方法
const customUpload = async (options: any) => {
  const { file, onProgress, onSuccess, onError } = options;
  
  try {
    isUploading.value = true;
    uploadProgress.value = 0;
    
    // 创建FormData
    const formData = new FormData();
    formData.append('file', file);
    
    // 如果有额外的数据，添加到FormData中
    if (props.data) {
      Object.keys(props.data).forEach(key => {
        formData.append(key, props.data[key]);
      });
    }
    
    // 调用附件上传API
    const response = await createAttachment(formData);
    
    // 处理成功响应
    if (response && response.data) {
      const fileUrl = response.data.url || response.data.path || response.data.filePath;
      if (fileUrl) {
        imageUrl.value = fileUrl;
        emit('update:modelValue', fileUrl);
        emit('success', fileUrl, file, response);
        ElMessage.success('上传成功');
        onSuccess(response);
      } else {
        throw new Error('无法获取文件地址');
      }
    } else {
      throw new Error('上传响应格式错误');
    }
  } catch (error: any) {
    ElMessage.error(`上传失败: ${error.message || '未知错误'}`);
    emit('error', error, file);
    onError(error);
  } finally {
    isUploading.value = false;
    uploadProgress.value = 0;
  }
};

// 上传进度
const handleProgress: UploadProps['onProgress'] = (event, file) => {
  uploadProgress.value = Math.round(event.percent || 0);
  emit('progress', event, file);
};
</script>

<style scoped>
.upload-component {
  display: inline-block;
}

/* 图片上传样式 */
.image-upload-content {
  position: relative;
}

.upload-placeholder {
  width: 178px;
  height: 178px;
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
  display: flex;
  align-items: center;
  justify-content: center;
}

.upload-placeholder:hover {
  border-color: var(--el-color-primary);
}

.upload-content {
  text-align: center;
}

.upload-icon {
  font-size: 28px;
  color: #8c939d;
  margin-bottom: 16px;
}

.upload-text {
  color: #8c939d;
  font-size: 14px;
}

/* 默认图片样式 */
.upload-component :deep(.el-upload img) {
  width: 178px;
  height: 178px;
  object-fit: cover;
  border-radius: 6px;
}

/* 拖拽上传样式 */
.drag-upload-content {
  text-align: center;
  padding: 40px 0;
}

.drag-upload-content .el-icon--upload {
  font-size: 67px;
  color: #c0c4cc;
  margin-bottom: 16px;
}

.drag-upload-content .el-upload__text {
  color: #606266;
  font-size: 14px;
  text-align: center;
}

.drag-upload-content .el-upload__text em {
  color: var(--el-color-primary);
  font-style: normal;
}

/* 按钮上传样式 */
.button-upload-content {
  display: inline-block;
}

/* 上传进度样式 */
.upload-progress {
  margin-top: 10px;
}

/* 提示文本样式 */
.el-upload__tip {
  font-size: 12px;
  color: var(--el-text-color-regular);
  margin-top: 7px;
}
</style>